package com.heer.api;

import android.content.Context;
import android.util.Log;

import com.google.gson.GsonBuilder;
import com.heer.api.callback.RequestCallback;
import com.heer.api.constants.IConstants;
import com.heer.api.sign.SDKRuntimeException;
import com.heer.api.sign.SignHelper;

import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManagerFactory;

import okhttp3.CacheControl;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Created by JS01 on 2016/6/7.
 */
public class Http {

    private static ApiService service;
    private static OkHttpClient client;

    /**
     * 返回APIService的对象，访问接口
     *
     * @return
     */
    public static ApiService getService() {
        if (client == null) {
            initClient();
        }

        if (service == null) {
            Retrofit retrofit = new Retrofit.Builder()
                    .client(client)
                    .baseUrl(IConstants.BASRURL_API)
                    .addConverterFactory(GsonConverterFactory
                            .create(new GsonBuilder()
                                    .registerTypeAdapterFactory(new EmptyCheckTypeAdapterFactory())
                                    .create()))
                    .build();
//            Retrofit retrofit = new Retrofit.Builder()
//                    .client(client)
//                    .baseUrl(IConstants.BASRURL)
//                    .addConverterFactory(FastJsonConverterFactory.create())
//                    .build();
            service = retrofit.create(ApiService.class);
        }
        return service;
    }

    /**
     * 返回APIService的对象，访问接口
     *
     * @param context 上下文，解析https 证书
     * @return
     */
    public static ApiService getService(Context context) {
        if (client == null) {
            initClient(context);
        }

        if (service == null) {
            Retrofit retrofit = new Retrofit.Builder()
                    .client(client)
                    .baseUrl(IConstants.BASRURL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            service = retrofit.create(ApiService.class);
        }
        return service;
    }

    /**
     * 初始化OKHttpClient
     */
    private static void initClient(Context context) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();

        //开启日志拦截器
        setLoggingInterceptor(builder);

        setHeaderInterceptor(builder);
        setTimeout(builder);
        //    setCertificates(builder,context);
        client = builder.build();
    }

    /**
     * 初始化OKHttpClient
     */
    private static void initClient() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();

        //开启日志拦截器
        setLoggingInterceptor(builder);
        setParamsInterceptor(builder);
        setTimeout(builder);
        client = builder.build();
    }

    /**
     * 设置超时和重试
     *
     * @param builder
     */
    private static void setTimeout(OkHttpClient.Builder builder) {
        //设置超时
        builder.connectTimeout(30, TimeUnit.SECONDS);
        builder.readTimeout(30, TimeUnit.SECONDS);
        builder.writeTimeout(30, TimeUnit.SECONDS);
        //错误重连
        builder.retryOnConnectionFailure(true);
    }

    /**
     * 设置https 证书
     *
     * @param builder
     */
    private static void setCertificates(OkHttpClient.Builder builder, Context context) {

        try {
            InputStream inputStream = null;
            // 下载的证书放到项目中的assets目录中
            inputStream = context.getAssets().open("rrzkey.cer");
            CertificateFactory certificateFactory = CertificateFactory
                    .getInstance("X.509");
            Certificate certificate = certificateFactory
                    .generateCertificate(inputStream);
            KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
            keyStore.load(null, null);
            keyStore.setCertificateEntry("trust", certificate);

            TrustManagerFactory trustManagerFactory = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
            builder.sslSocketFactory(sslContext.getSocketFactory());
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String arg0, SSLSession arg1) {
                    return true;
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 公共参数拦截器
     *
     * @param builder
     */
    private static void setParamsInterceptor(OkHttpClient.Builder builder) {
        if (builder != null) {
            Interceptor paramsInterceptor = new Interceptor() {
                @Override
                public Response intercept(Chain chain) {
                    try {

                        Request originalRequest = chain.request();

                        Request.Builder requestBuilder = originalRequest.newBuilder();

                        SignHelper sign = new SignHelper("");

                        if (originalRequest.body() instanceof FormBody) {

                            FormBody.Builder newFormBody = new FormBody.Builder();

                            FormBody oldFormBody = (FormBody) originalRequest.body();

                            for (int i = 0; i < oldFormBody.size(); i++) {

                                newFormBody.addEncoded(oldFormBody.encodedName(i), oldFormBody.encodedValue(i));

                                sign.SetParameter(oldFormBody.encodedName(i), oldFormBody.encodedValue(i));

                            }

                            for (Object o : sign.getParameters().entrySet()) {

                                Map.Entry entry = (Map.Entry) o;

                                String key = entry.getKey().toString();

                                String val = entry.getValue().toString();

                                newFormBody.add(key, val);

                            }

                            newFormBody.add("sign", sign.getSign());

                            newFormBody.add("method", originalRequest.url().toString().replace(IConstants.BASRURL, ""));

                            for (int i = 0; i < newFormBody.build().size(); i++) {

                                Log.e("tag", "intercept: " + "key=" + newFormBody.build().encodedName(i) + "&&value==" + newFormBody.build().encodedValue(i));

                            }

                            requestBuilder.method(originalRequest.method(), newFormBody.build());
                        }

                        Request newRequest = requestBuilder.build();

                        return chain.proceed(newRequest);

                    } catch (SDKRuntimeException e) {
                        e.printStackTrace();
                        return null;
                    } catch (IOException e) {
                        e.printStackTrace();
                        return null;
                    }
                }
            };
            builder.addInterceptor(paramsInterceptor);
        }
    }

    /**
     * 头部拦截器
     *
     * @param builder
     */
    private static void setHeaderInterceptor(OkHttpClient.Builder builder) {
        if (builder != null) {
            Interceptor headerInterceptor = new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request originalRequest = chain.request();
                    Request.Builder requestBuilder = originalRequest.newBuilder()
                            .header("AppType", "POST")
                            .header("Content-Type", "application/json")
                            .header("Accept", "application/json")
                            .method(originalRequest.method(), originalRequest.body());
                    Request request = requestBuilder.build();
                    return chain.proceed(request);
                }
            };
            builder.addInterceptor(headerInterceptor);
        }
    }

    /**
     * 日志拦截器
     *
     * @param builder
     */
    private static void setLoggingInterceptor(OkHttpClient.Builder builder) {
        if (builder != null) {
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            builder.addInterceptor(loggingInterceptor);
        }
    }

    /**
     * GET请求
     *
     * @param url      请求链接
     * @param params   请求参数
     * @param callback 请求回调 为防止内存泄漏，callback用弱引用包装
     */
    public static <T> void get(String url, Map<String, String> params, final RequestCallback<T> callback) {
        if (client == null) {
            initClient();
        }
        final WeakReference<RequestCallback<T>> weakReference = new WeakReference<>(callback);
        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                urlBuilder.addQueryParameter(key, value);
            }
        }
        HttpUrl httpUrl = urlBuilder.build();
        final Request request = new Request.Builder()
                .url(httpUrl)
                .cacheControl(CacheControl.FORCE_NETWORK)
                .get()
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                RequestCallback<T> callback1 = weakReference.get();
                if (callback1 != null) {
                    int code = -1;
                    String error = e.getLocalizedMessage();
                    callback1.onFailure(code, error);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                RequestCallback<T> callback1 = weakReference.get();
                if (response.isSuccessful()) {
                    ResponseBody body = response.body();
                    T t = (T) body.string();
                    if (callback1 != null) {
                        callback1.onSuccess(t);
                    }
                } else {
                    int code = response.code();
                    String error = response.message();
                    if (callback1 != null) {
                        callback1.onFailure(code, error);
                    }
                }
            }
        });
    }

    /**
     * POST请求
     *
     * @param url      请求链接
     * @param params   请求参数
     * @param callback 请求回调 为防止内存泄漏，callback用弱引用包装
     */
    public static <T> void post(String url, Map<String, String> params, final RequestCallback<T> callback) {
        if (client == null) {
            initClient();
        }

        final WeakReference<RequestCallback<T>> weakReference = new WeakReference<>(callback);
        FormBody.Builder bodyBuilder = new FormBody.Builder();
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                bodyBuilder.add(key, value);
            }
        }
        FormBody formBody = bodyBuilder.build();

        Request request = new Request.Builder()
                .cacheControl(CacheControl.FORCE_NETWORK)
                .url(url)
                .post(formBody)
                .build();
        Call call = client.newCall(request);

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                RequestCallback<T> callback1 = weakReference.get();
                if (callback1 != null) {
                    int code = -1;
                    String error = e.getLocalizedMessage();
                    callback1.onFailure(code, error);
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                RequestCallback<T> callback1 = weakReference.get();
                if (response.isSuccessful()) {
                    ResponseBody body = response.body();
                    T t = (T) body.string();
                    if (callback1 != null) {
                        callback1.onSuccess(t);
                    }
                } else {
                    int code = response.code();
                    String error = response.message();
                    if (callback1 != null) {
                        callback1.onFailure(code, error);
                    }
                }
            }
        });
    }
}
